查看原文
其他

一码通的时代,如何实现二维码的检测和解码?手把手教你!

肖铃 博文视点Broadview 2022-08-23

👆点击“博文视点Broadview”,获取更多书讯

深度学习计算机视觉的惊人成绩让计算机视觉的传统算法在目标检测领域逐渐淡出人们的视野,但是在许多应用程序中,这些传统算法依旧发挥着重要的作用。

它们在出现伊始也产生了轰动的效果,如 HOG 算法在行人检测方面的巨大优势,因此,若想深入学习图像处理,还是很有必要重温这些传统算法的。

OpenCV 中的 objdetect 模块封装了传统计算机视觉的目标检测算法,引入该模块需要包含头文件"opencv2/objdetect.hpp",通过该头文件,读者可以了解模块封装的算法。

该头文件的定义及各模块具体解读大家可以阅读《学习OpenCV 4:基于Python的算法实战》一书或查看源文件。

如今这个到处扫码的时代,二维码在我们生活中发挥了重要作用,前段时间“西安一码通崩溃”事件也引发了不少讨论,所以本文就主要来看一下二维码方面的应用案例!

首先介绍一下二维码检测器类 QRCodeDetector 的定义:

class CV_EXPORTS_W QRCodeDetector{public: CV_WRAP QRCodeDetector();    ~QRCodeDetector();
/** 设置二维码水平扫描期间停止标记检测使用的epsilon*/ CV_WRAP void setEpsX(double epsX); /** 设置二维码垂直扫描期间停止标记检测使用的epsilon*/    CV_WRAP void setEpsY(double epsY);
/** 图像中的二维码检测并返回二维码检测包围框矩形*/    CV_WRAP bool detect(InputArray img, OutputArray points) const;
/** 二维码解码*/ CV_WRAP std::string decode(InputArray img, InputArray points,                                         OutputArray straight_qrcode = noArray());
/** 曲面二维码解码*/CV_WRAP cv::String decodeCurved(InputArray img, InputArray points, OutputArray straight_qrcode = noArray()); /** 二维码检测并解码*/ CV_WRAP std::string detectAndDecode(InputArray img, OutputArray points=noArray(), OutputArray straight_qrcode = noArray()); /** 曲面二维码检测并解码*/ CV_WRAP std::string detectAndDecodeCurved(InputArray img, OutputArray points=noArray(), OutputArray straight_qrcode = noArray()); /** 检测图像中的多个二维码*/ CV_WRAP bool detectMulti(InputArray img, OutputArray points) const; /** 多个二维码解码*/ CV_WRAP bool decodeMulti( InputArray img, InputArray points, CV_OUT std::vector<std::string>& decoded_info, OutputArrayOfArrays straight_qrcode = noArray()    ) const;
/** 多个二维码检测并解码*/ CV_WRAP bool detectAndDecodeMulti( InputArray img, CV_OUT std::vector<std::string>& decoded_info, OutputArray points = noArray(), OutputArrayOfArrays straight_qrcode = noArray() ) const;
protected: struct Impl; Ptr<Impl> p;};}

#include "opencv2/objdetect/detection_based_tracker.hpp"#endif


二维码有多种编码方式,常用的二维码为 QR Code。

二维码如果需要被识别,则第一步是在图像中检测到二维码,第二步是对检测到的二维码进行解码。

二维码检测

OpenCV 中封装了二维码检测类 QRCodeDetector,其中用于二维码检测的成员函数为 detect,其定义如下:

retval, points = detect(self, img, points=None) 

参数说明如下。

  • img:输入图像。

  • points:返回检测到包围二维码的最小四边形(返回值)。

  • retval:函数调用状态,调用成功返回 true。

本案例使用的输入图像如下图所示。

图1

使用 OpenCV 进行二维码检测的案例代码如下:

import cv2

#输入图像读取image = cv2.imread("src.png")#创建QRCodeDetector对象qrDecoder = cv2.QRCodeDetector()#二维码检测_, bbox = qrDecoder.detect(image)bbox = bbox.astype(int)#检测结果显示cv2.line(image, tuple(bbox[0][0]), tuple(bbox[0][1]), (255, 0, 0), 3)cv2.line(image, tuple(bbox[0][1]), tuple(bbox[0][2]), (255, 0, 0), 3)cv2.line(image, tuple(bbox[0][2]), tuple(bbox[0][3]), (255, 0, 0), 3)cv2.line(image, tuple(bbox[0][3]), tuple(bbox[0][0]), (255, 0, 0), 3)#结果显示cv2.imshow("Results", image)cv2.waitKey(0)

二维码检测结果如下图所示。

图2

二维码解码

QRCodeDetector 类的成员函数 decode 负责二维码的解码工作,其定义如下:

retval, straight_qrcode = decode(self, img, points, straight_qrcode=None)

参数说明如下。

  • img:输入图像。

  • points:检测到的包围二维码的矩形。

  • straight_qrcode:可选的输出图像,该图像中包含经过校正和二值化的二维码(返 回值)。

  • retval:解码的数据结果(返回值)。

二维码解码的案例代码如下:

import cv2

#输入图像读取image = cv2.imread("src.png")#创建QRCodeDetector对象qrDecoder = cv2.QRCodeDetector()#二维码检测_, bbox = qrDecoder.detect(image)#二维码解码data, _ = qrDecoder.decode(image, bbox)print("Decoded Data : {}".format(data))

对检测到的二维码(见上图)进行解码,结果如下:

Decoded Data :  《深度学习计算机视觉实战》肖铃,刘东著:本书共有近 50 个案例,全书内容共分为四个部分:一、深度学习和计算机视觉算法理论基础;二、OpenCV 图像处 理讲解;三、计算机视觉实战项目;四、模型部署。

QRCodeDetector 类的成员函数 detectAndDecode 封装了二维码检测和解码的功能, 其定义如下:

retval, points, straight_qrcode = detectAndDecode (self, img, points, straight_qrcode=None)

参数说明如下。

  • img:输入图像。

  • points:检测到的包围二维码的矩形(返回值)。

  • straight_qrcode:可选的输出图像,包含校正和二值化的二维码(返回值)。

  • retval:解码的结果数据(返回值)。

使用 detectAndDecode 函数进行二维码检测和解码的案例代码如下:

import cv2import time
#输入图像读取image = cv2.imread("src.png")#创建QRCodeDetector对象qrDecoder = cv2.QRCodeDetector()#二维码检测t = time.time()data, bbox, _ = qrDecoder.detectAndDecode(image)#检测耗时输出print("Time Taken for Detect and Decode : {:.3f} seconds".format(time.time() - t))#二维码解码结果输出print("Decoded Data : {}".format(data))#检测结果显示bbox = bbox.astype(int)cv2.line(image, tuple(bbox[0][0]), tuple(bbox[0][1]), (255, 0, 0), 3)cv2.line(image, tuple(bbox[0][1]), tuple(bbox[0][2]), (255, 0, 0), 3)cv2.line(image, tuple(bbox[0][2]), tuple(bbox[0][3]), (255, 0, 0), 3)cv2.line(image, tuple(bbox[0][3]), tuple(bbox[0][0]), (255, 0, 0), 3)#结果显示cv2.imshow("QRCode Detect", image)cv2.waitKey(0)

二维码检测并解码的时间和解码结果输出信息如下:

Time Taken for Detect and Decode : 0.839 seconds  Decoded Data : 《深度学习计算机视觉实战》肖铃,刘东著:本书共有近 50 个案例,全书内容共分为四个部分:一、深度学习和计算机视觉算法理论基础;二、OpenCV 图像处 理讲解;三、计算机视觉实战项目;四、模型部署。

读者可以在网上找到二维码生成平台,如果想使用 OpenCV 正确解码,则在二 维码生成时注意码制选择“QR Code”。

进阶:条形码与二维码

条形码(或一维码)是一种信息自动识别技术,图案由反射率相差极大的宽度不等的黑白 条平行排列而成。

条形码技术实现了信息快速录入计算机,多见于超市商品和图书上,该技术 实现了物品的自动管理,在零售业、图书管理、仓储物流等许多领域有着广泛应用。

常用的条形码编码方式包括 EAN 码、39 码、交叉 25 码、UPC 码、128 码、93 码、ISBN 码等,下图为图书中常用的 ISBN 码条形码。

二维码因为其信息量大、储存信息多样、成本低廉等优点在近几年开始渗入生活的方方面面,如付款码、信息分享的二维码等。

二维码是在平面(或二维方向)上按一定规律分布的、 黑白或彩色与白色相间的、记录数据符号信息的图形,如下图所示。

常用的二维码编码方式有 PDF417、Data Matrix、QR Code、Code 49、Code 16K、 Code one 等,如 12.4 节中的案例使用的二维码编码方式为 QR Code。

条形码与二维码的对比如下。

  • 二维码包含的信息量远大于条形码包含的信息量:条形码包含的内容只能是字母和数 字,尺寸较大,因而空间利用率较低,容纳的数据量一般为 30 个字符左右。二维码包 含的内容为字母、数字、汉字、字符、片假名等,最大可承载信息量为 1850 个字符, 信息内容多样且信息量巨大。

  • 两种条码的信息表达方式不同:条形码只能在水平方向上表达信息,在垂直方向上不 表达信息,具有一定的高度(为了便于条码设备的对准,从而进行信息读取)。二维码在二维层面上都有信息表达,因此可以存储的信息量更大。

条形码纠错能力较差,若条码有破损,则不能被读取;二维码在有部分破损的情况下,信 息也可以被正常读取,纠错率高达 30%。

本文摘自《学习OpenCV 4:基于Python的算法实战》一书!欢迎阅读本书了解更多OpenCV 4的更多案例!

▊《学习OpenCV 4:基于Python的算法实战》

肖铃 


  • 学习目标:为那些想学习和掌握OpenCV的读者提供一本“看了就能学会”的书。

  • 超过100个案例,使用简洁生动的语言,和更新的Python语言实现代码去描述相应的操作方法


本书使用Python语言,以OpenCV源码结构中的模块为章节,系统地介绍了OpenCV在图像处理和计算机视觉领域的应用。

本书不仅适合图像处理和计算机视觉领域的读者阅读,还适合高校师生、专业技术人员、图像处理爱好者、深度学习计算机视觉领域爱好者参考使用。


(五折专属优惠,速抢!)





如果喜欢本文
欢迎 在看留言分享至朋友圈 三连


 热文推荐  





▼点击阅读原文,查看本书详情~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存